package org.example.camundaapp.utils;

import org.camunda.bpm.engine.impl.util.IoUtil;
import org.camunda.bpm.model.bpmn.Bpmn;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.image.impl.DefaultProcessDiagramGenerator;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
/**
 * @className: BpmnToPngConverter
 * @author: ZHRJ
 * @date: 2025-06-30 10:18
 * @Version: 1.0
 * @description:
 */
public class BpmnToImageConverter {


    /**
     * 将BPMN XML转换为PNG图片
     * @param bpmnXml
     * @return
     * @throws Exception
     */
    public static byte[] convertBpmnXmlToPngBytes(String bpmnXml) throws Exception {
        // 1. 解析bpmnXml为BpmnModel
        BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
        //InputStream xmlInput = new ByteArrayInputStream(bpmnXml.getBytes("UTF-8"));
        //BpmnModel bpmnModel = xmlConverter.convertToBpmnModel(xmlInput, false, false);
        BpmnModel bpmnModel = xmlConverter.convertToBpmnModel(
                () -> new ByteArrayInputStream(bpmnXml.getBytes(StandardCharsets.UTF_8)),
                false, // validateSchema
                true  // processAllElements
        );


        // 2. 生成流程图
        DefaultProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
        InputStream pngInput = diagramGenerator.generateDiagram(
                bpmnModel,
                "png",
                Collections.<String>emptyList(), // activity高亮 高亮活动id列表
                Collections.<String>emptyList(), // flow高亮 高亮流程流id列表
                "宋体", // activityFontName
                "宋体", // labelFontName
                "宋体", // annotationFontName
                null, // classloader，作用加载自定义字体，如宋体
                1.0,    // scaleFactor
                true // drawSequenceFlowNameWithNoLabel，作用：绘制流程图时，如果流程图上某个流程节点的连线有名称，则将连线的名称绘制在连线上，否则不绘制。
        );

        // 3. 转为byte[]
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[8192];
        int length;
        while ((length = pngInput.read(buffer)) != -1) {
            baos.write(buffer, 0, length);
        }
        return baos.toByteArray();
    }


    /**
     * 从输入流解析 BPMN 模型并转换为 PNG 图片字节数组
     * @param bpmnInputStream BPMN 输入流
     * @return PNG 图片字节数组
     * @throws  转换过程中可能出现的异常
     */
    public static byte[] convertBpmnInputStreamToPngBytes(InputStream bpmnInputStream) throws Exception {
        // 从输入流解析 BPMN 模型
        BpmnModelInstance modelInstance = Bpmn.readModelFromStream(bpmnInputStream);
        // 将 BpmnModelInstance 转换为字节数组
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        Bpmn.writeModelToStream(outputStream, modelInstance);
        byte[] bpmnBytes = outputStream.toByteArray();

        // 将字节数组转换为 BpmnModel
        BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
        // 使用 Lambda 表达式将 ByteArrayInputStream 包装成 InputStreamProvider
        BpmnModel bpmnModel = xmlConverter.convertToBpmnModel(
                () -> new ByteArrayInputStream(bpmnBytes),
                false,
                false
        );


        // 生成流程图
        ProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
        InputStream pngInput = diagramGenerator.generateDiagram(
                bpmnModel,
                "png",
                Collections.emptyList(),
                Collections.emptyList(),
                "宋体",
                "宋体",
                "宋体",
                null,
                1.0,
                true
        );

        // 转换为字节数组
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[8192];
        int length;
        while ((length = pngInput.read(buffer)) != -1) {
            baos.write(buffer, 0, length);
        }
        return baos.toByteArray();
    }
}
